import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:ichinesereader/constants.dart';
import 'package:ichinesereader/controller/cache.dart';
import 'package:ichinesereader/models/assessment/assessmentGradingDto.dart';
import 'package:ichinesereader/models/assessment/assessmentRecordsResult.dart';
import 'package:ichinesereader/models/book/BookItem.dart';
import 'package:ichinesereader/models/book/bookAssigned.dart';
import 'package:ichinesereader/models/common/StatusMessageResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationBenchmarkReportResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationBookReportResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationBooksResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationClassReportResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationOverviewResult.dart';
import 'package:ichinesereader/models/evaluation/evaluationSkillProgressResult.dart';
import 'package:ichinesereader/models/evaluation/linguisticKnowledgeResult.dart';
import 'package:ichinesereader/models/evaluation/skillPointsResult.dart';
import 'package:ichinesereader/models/evaluation/proficiencySkillsResult.dart';
import 'package:ichinesereader/models/evaluation/randomBookResult.dart';
import 'package:ichinesereader/service/book.dart';
import 'package:ichinesereader/service/evaluation.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:ichinesereader/utils/log.dart';

class EvaluationController extends GetxController with StateMixin<dynamic> {
  EvaluationServiceProvider _evaluationServiceProvider =
      new EvaluationServiceProvider();
  var box = Hive.box('appconfig');
  BookServiceProvider _bookServiceProvider = new BookServiceProvider();
  List<QuestionRecord> _evaluationRecordItems = <QuestionRecord>[].obs;
  List<QuestionRecord> get evaluationRecordItems => this._evaluationRecordItems;
  List<BookItem> _evaluationBooks = <BookItem>[].obs;
  List<BookItem> get evaluationBooks => this._evaluationBooks;
  List<BookItem> _selectedEvaluationBooks = <BookItem>[].obs;
  List<BookItem> get selectedEvaluationBooks => this._selectedEvaluationBooks;
  bool _refresh = true;
  bool get forceRefresh => this._refresh;

  Rx<EvaluationBook> _evaluationRandomBook =
      Rx<EvaluationBook>(EvaluationBook());
  Rx<EvaluationBook> get evaluationRandomBook => this._evaluationRandomBook;

  Rx<EvaluationOverViewData> _evaluationOverviewData =
      Rx<EvaluationOverViewData>(EvaluationOverViewData());
  Rx<EvaluationOverViewData> get evaluationOverviewData =>
      this._evaluationOverviewData;
  Rx<EvaluationOverViewData> _benchmarkOverviewData =
      Rx<EvaluationOverViewData>(EvaluationOverViewData());
  Rx<EvaluationOverViewData> get benchmarkOverviewData =>
      this._benchmarkOverviewData;
  Rx<BenchmarkReportData> _benchmarkReportData =
      Rx<BenchmarkReportData>(BenchmarkReportData());
  Rx<BenchmarkReportData> get benchmarkReportData => this._benchmarkReportData;
  List<ProficiencySkillsDataTree> _evaluationSkillsDataTree =
      <ProficiencySkillsDataTree>[].obs;
  List<ProficiencySkillsDataTree> get evaluationSkillsDataTree =>
      this._evaluationSkillsDataTree;
  List<SkillPointsDataTree> _evaluationSkillPointsDataTree =
      <SkillPointsDataTree>[].obs;
  List<SkillPointsDataTree> get evaluationSkillPointsDataTree =>
      this._evaluationSkillPointsDataTree;

  Rx<LinguisticKnowledgeData> _evaluationLinguisticKnowledgeData =
      Rx<LinguisticKnowledgeData>(LinguisticKnowledgeData());
  Rx<LinguisticKnowledgeData> get evaluationLinguisticKnowledgeData =>
      this._evaluationLinguisticKnowledgeData;

  List<EvaluationBookReport> _studentEvaluationDetails =
      <EvaluationBookReport>[].obs;
  List<EvaluationBookReport> get studentEvaluationDetails =>
      this._studentEvaluationDetails;
  Rx<EvaluationBookReportResult> _evaluationBookReportResult =
      Rx<EvaluationBookReportResult>(EvaluationBookReportResult());
  Rx<EvaluationBookReportResult> get evaluationBookReportResult =>
      this._evaluationBookReportResult;

  List<SkillProgressItem> _evaluationSkillProgressData =
      <SkillProgressItem>[].obs;
  List<SkillProgressItem> get evaluationSkillProgressData =>
      this._evaluationSkillProgressData;

  List<SkillProgressItem> _evaluationProficiencySkillProgressData =
      <SkillProgressItem>[].obs;
  List<SkillProgressItem> get evaluationProficiencySkillProgressData =>
      this._evaluationProficiencySkillProgressData;

  RxString _currentLevel = '1'.obs;
  RxString get currentLevel => this._currentLevel;

  @override
  void onInit() {
    super.onInit();
    var isTeacher = box.get(CacheManagerKey['nanhairole'].toString()) ==
        Constants.NanhaiRole_Teacher;
    var level;
    try {
      if (isTeacher) {
        level  = (box.get(CacheManagerKey['eveluationlevel'].toString(),
                                defaultValue: 1) as double)
                            .toInt();
      } else {
        level = int.tryParse(
                box.get("UserLevel").toString().replaceAll('level', '')) ??
            1;
      }
    } catch (error) {
      level = 1;
    }

    this._currentLevel.value = level.toString();
  }

  @override
  dispose() {
    super.dispose();
  }

  void addToSelectedBookItems(
      BookItem book, NanhaiBookReadingTypes readingType) {
    if (readingType == NanhaiBookReadingTypes.evaluation) {
      if (this
          ._selectedEvaluationBooks
          .where((element) => element.bookId == book.bookId)
          .isEmpty) {
        this._selectedEvaluationBooks.add(book);
      }
      var bk = this
          ._evaluationBooks
          .where((element) => element.bookId == book.bookId)
          .first;
      if (bk.bookId != null) {
        bk.selected = true;
        change(this._evaluationBooks, status: RxStatus.success());
      }
    }
  }

  void removeFromSelectedBookItems(
      BookItem book, NanhaiBookReadingTypes readingType) {
    if (readingType == NanhaiBookReadingTypes.evaluation) {
      if (this
          ._selectedEvaluationBooks
          .where((element) => element.bookId == book.bookId)
          .isNotEmpty) this._selectedEvaluationBooks.remove(book);
      var bk = this
          ._evaluationBooks
          .where((element) => element.bookId == book.bookId)
          .first;
      if (bk.bookId != null) {
        bk.selected = false;
        change(this._evaluationBooks, status: RxStatus.success());
      }
    }
  }

  void fetchEvaluationBookReportData(String classId, String? bookcode) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider.getEvaluationBookReport(
          classId, bookcode);
      if (response.statusCode == 200) {
        var data = evaluationBookReportResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationBookReportResult.value = data;
          change(_evaluationBookReportResult, status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationClassReportData(String classId, String? level) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider.getEvaluationClassReport(
          classId, level);
      if (response.statusCode == 200) {
        var data = evaluationClassReportResultFromJson(response.bodyString);
        if (data.result != null) {
          _studentEvaluationDetails
              .assignAll(data.result?.list as List<EvaluationBookReport>);
          change(_studentEvaluationDetails, status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationLinguisticKnowledgesProgressData(
      String? classId, String? level, String? type) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider
          .getEvaluationLinguisticKnowledges(classId, level, type);
      if (response.statusCode == 200) {
        var data = evaluationSkillProgressResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationSkillProgressData
              .assignAll(data.result?.list as List<SkillProgressItem>);
          change(_evaluationSkillProgressData, status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationProficiencySkillProgressData(
      String? classId, String? level, String? type) async {
    try {
      EasyLoading.show();
      // change(_evaluationProficiencySkillProgressData,
      //     status: RxStatus.loading());
      var response = await _evaluationServiceProvider
          .getEvaluationProficiencySkillProgress(classId, level, type);
      if (response.statusCode == 200) {
        var data = evaluationSkillProgressResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationProficiencySkillProgressData
              .assignAll(data.result?.list as List<SkillProgressItem>);
          change(_evaluationProficiencySkillProgressData,
              status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationLinguisticKnowledgesData(
      String? classId, String? level, String? type) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider
          .getEvaluationLinguisticKnowledges(classId, level, type);
      if (response.statusCode == 200) {
        var data =
            evaluationLinguisticKnowledgeResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationLinguisticKnowledgeData.value =
              data.result as LinguisticKnowledgeData;
          change(_evaluationLinguisticKnowledgeData,
              status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationSkillPointsData(String classId, String? level) async {
    try {
      //change(_evaluationSkillPointsDataTree, status: RxStatus.loading());
      EasyLoading.show();
      var response = await _evaluationServiceProvider.getEvaluationSkillPoints(
          classId, level);
      if (response.statusCode == 200) {
        var data = evaluationSkillPointsResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationSkillPointsDataTree
              .assignAll(data.result?.tree as List<SkillPointsDataTree>);
          change(_evaluationSkillPointsDataTree, status: RxStatus.success());
        }
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchEvaluationProficiencySkillsData(
      String classId, String? level, String? skillId) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider
          .getEvaluationProficiencySkills(classId, level, skillId);
      if (response.statusCode == 200) {
        var data = evaluationSkillsResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationSkillsDataTree
              .assignAll(data.result?.tree as List<ProficiencySkillsDataTree>);
          change(_evaluationSkillsDataTree, status: RxStatus.success());
        }
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<EvaluationOverViewData> fetchEvaluationOverviewData(
      String classId) async {
    var overViewData = new EvaluationOverViewData();
    try {
      EasyLoading.show();
      var response =
          await _evaluationServiceProvider.getEvaluationOverview(classId);
      if (response.statusCode == 200) {
        var data = evaluationOverviewResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationOverviewData.value = data.result as EvaluationOverViewData;
          overViewData = _evaluationOverviewData.value;
          change(_evaluationOverviewData, status: RxStatus.success());
        }
        // else
        //   change(null, status: RxStatus.empty());
      } else {
        //change(null, status: RxStatus.error(response.statusCode.toString()));
        change(null, status: RxStatus.empty());
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return overViewData;
  }

  Future<EvaluationOverViewData> fetchBenchmarkOverviewData(
      String classId) async {
    var overViewData = new EvaluationOverViewData();
    try {
      EasyLoading.show();
      var response =
          await _evaluationServiceProvider.getBenchmarkOverview(classId);
      if (response.statusCode == 200) {
        var data = evaluationOverviewResultFromJson(response.bodyString);
        if (data.result != null) {
          _benchmarkOverviewData.value = data.result as EvaluationOverViewData;
          overViewData = _benchmarkOverviewData.value;
          change(_benchmarkOverviewData, status: RxStatus.success());
        }
        // else
        //   change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return overViewData;
  }

  void refreshEvaluationOverviewData(String classId) async {
    if (this._evaluationOverviewData.value.actflLevel != null &&
        this._evaluationOverviewData.value.actflLevel!.length > 0) {
      change(_evaluationOverviewData, status: RxStatus.success());
    } else {
      fetchEvaluationOverviewData(classId);
    }
  }

  void refreshBenchmarkOverviewData(String classId) async {
    if (this._benchmarkOverviewData.value.actflLevel != null &&
        this._benchmarkOverviewData.value.actflLevel!.length > 0) {
      change(_benchmarkOverviewData, status: RxStatus.success());
    } else {
      fetchBenchmarkOverviewData(classId);
    }
  }

  void doRefresh() async {
    try {
      EasyLoading.show();
      this._refresh = false;
      await Future.delayed(Duration(milliseconds: 10), (() {
        this._refresh = true;
      }));
      change(_refresh, status: RxStatus.success());
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void submitEvaluationRecordGrading(AssessmentGradingDto dto) async {
    try {
      var response =
          await _evaluationServiceProvider.submitEvaluationGrade(dto);
      if (response.statusCode == 200) {}
    } catch (error) {
      Log.debug(error);
    }
  }

  void fetchEvaluationBooks(String? page, String? limit, String? type,
      String level, String classId) async {
    try {
      //change(null, status: RxStatus.loading());
      EasyLoading.show();
      List<String> bookIds = [];
      var response = await _evaluationServiceProvider.getEvaluationBooks(
          limit, page, type, level);
      if (response.statusCode == 200) {
        var data = evaluationBooksResultFromJson(response.bodyString);
        final box = Hive.box('appconfig');

        List<BookItem> items = [];
        var _language = box.get('UserLanguage') ?? 'Simplified';
        for (int i = 0; i < data.list!.length; i++) {
          BookItem item = BookItem();
          item.bookCode = data.list![i].bookCode;
          item.bookId = data.list![i].bookId;
          item.viewMode = data.list![i].viewMode;
          item.simBookImageLink =
              "https://resources.ichinesereader.com/books/${item.bookCode}/0.jpg";
          if (_language == 'Traditional') {
            item.bookTitle = data.list![i].titleTraditional ?? '';
            item.bookImageLink =
                "https://resources.ichinesereader.com/books/${item.bookCode}/0t.jpg";
            item.description = data.list![i].descriptionTraditional != null
                ? data.list![i].descriptionTraditional
                : data.list![i].titleTraditional;
            // item.bookImageLink = insertCharAt(item.simBookImageLink!,
            //     item.simBookImageLink!,  item.simBookImageLink, "t").replaceAll('.gif', '.jpg').replaceAll('.gif', '.jpg');
          } else {
            item.bookTitle = data.list![i].title ?? '';
            item.bookImageLink = item.simBookImageLink;
            item.description = data.list![i].description != null
                ? data.list![i].description
                : data.list![i].title;
          }
          item.bookLevel = data.list![i].level.toString();
          item.color = Constants.bookLevelColors
                  .where((element) => element.level == data.list![i].level)
                  .first
                  .color ??
              '#808080';
          if (item.bookCode != null) {
            items.add(item);
            bookIds.add(item.bookId.toString());
          }
        }
        _evaluationBooks.assignAll(items);
        if (_evaluationBooks.length > 0) {
          _evaluationBooks.sort((a, b) {
            var end1 = a.bookCode as String;
            var end2 = b.bookCode as String;
            return end1.compareTo(end2);
          });
          change(_evaluationBooks, status: RxStatus.success());

          bool isTeacher = box.get(CacheManagerKey['nanhairole'].toString()) ==
              Constants.NanhaiRole_Teacher;
          if (isTeacher) {
            var _classId = box.get(CacheManagerKey['currentclass'].toString());
            checkBookAssignmentStatus(
                _classId, bookIds, NanhaiBookReadingTypes.evaluation);
          }
        } else
          change(_evaluationBooks, status: RxStatus.empty());
      } else {
        change(_evaluationBooks, status: RxStatus.empty());
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void checkBookAssignmentStatus(String classId, List<String> bookIds,
      NanhaiBookReadingTypes readingType) async {
    try {
      var response =
          await _bookServiceProvider.checkIfBookAssigned(classId, bookIds);
      if (response.statusCode == 200) {
        var data = bookAssignedFromJson(response.bodyString);
        if (readingType == NanhaiBookReadingTypes.evaluation) {
          this._evaluationBooks.forEach((bookItem) {
            var index =
                data.indexWhere((element) => element.bookId == bookItem.bookId);
            if (index != -1) {
              bookItem.ifAssigned = data[index].ifAssigned ?? false;
            }
          });
          change(this._evaluationBooks, status: RxStatus.success());
        }
      }
    } catch (e) {}
  }

  Future<StatusMessageResult> fetchEvaluationRandomBook(String level) async {
    var _statusMessageResult = StatusMessageResult();
    EasyLoading.show();
    try {
      var response =
          await _evaluationServiceProvider.getEvaluationRandomBook(level);
      if (response.statusCode == 200) {
        var data = evaluationRandomBookResultFromJson(response.bodyString);
        if (data.result != null) {
          _evaluationRandomBook.value = data.result as EvaluationBook;
          change(_evaluationRandomBook, status: RxStatus.success());
          _statusMessageResult.status = 1000;
        } else {
          _statusMessageResult.status = 0;
        }
      } else {
        _statusMessageResult.status = 0;
        change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      }
    } catch (error) {
      _statusMessageResult.status = 0;
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return _statusMessageResult;
  }

  Future<List<QuestionRecord>> fetchEvaluationRecords(
      String? limit, String? page, String? type, String? classId) async {
    try {
      EasyLoading.show();
      _evaluationRecordItems.clear();
      var response = await _evaluationServiceProvider
          .getEvaluationRecordsByClass(limit, page, type, classId);
      if (response.statusCode == 200) {
        var data = assessmentRecordsResultFromJson(response.bodyString);
        _evaluationRecordItems.assignAll(data.list as List<QuestionRecord>);
        if (_evaluationRecordItems.length > 0) {
          _evaluationRecordItems.sort((a, b) {
            var end1 = a.committedTime as int;
            var end2 = b.committedTime as int;
            return end2.compareTo(end1);
          });
          change(_evaluationRecordItems, status: RxStatus.success());
        } else
          change(null, status: RxStatus.empty());
      } else {
        //change(null, status: RxStatus.error(response.statusCode.toString()));
        change(null, status: RxStatus.empty());
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return _evaluationRecordItems;
  }

  Future<BenchmarkReportData> fetchBenchmarkReportUserData(
      String userName, String level) async {
    var benchmarkReport = new BenchmarkReportData();
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider
          .getBenchmarkReportUserData(userName, level);
      if (response.statusCode == 200) {
        var data = evaluationBenchmarkReportResultFromJson(response.bodyString);
        if (data.result != null) {
          _benchmarkReportData.value = data.result as BenchmarkReportData;
          benchmarkReport = _benchmarkReportData.value;
          change(_benchmarkReportData, status: RxStatus.success());
        }
        // else
        //   change(null, status: RxStatus.empty());
      } else {
        change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      //change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return benchmarkReport;
  }

  void updateCurrentLevel(String level) {
    this._currentLevel.value = level;
  }
}
